// @Author EthanScriptOn
// @Desc
package util

import (
	"fmt"
	"reflect"
	"strings"
	"unicode"
)

// Print Format the output item
func Print(item interface{}) string {
	of := reflect.ValueOf(item)
	if of.IsZero() {
		return "nil"
	}
	kind := of.Type().Kind()
	switch kind {
	case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Array, reflect.Map:
		return fmt.Sprint(item)
	case reflect.Struct:
		return fmt.Sprintf("[%+v]", item)
	case reflect.Func:
		param := ""
		out := ""
		itemType := reflect.TypeOf(item)
		outLen := itemType.NumOut()
		paramLen := itemType.NumIn()
		maxLen := outLen
		if paramLen > maxLen {
			maxLen = paramLen
		}
		index := 0
		for {
			if index == maxLen {
				break
			}
			if index < outLen {
				out += itemType.Out(index).Kind().String()
				if index != outLen-1 {
					out += ","
				}
			}
			if index < paramLen {
				param += itemType.In(index).Kind().String()
				if index != paramLen-1 {
					param += ","
				}
			}
			index++
		}
		return fmt.Sprintf("fun([%v])([%v])", param, out)
	case reflect.Pointer:
		return fmt.Sprint(Print(of.Elem().Interface()))
	default:
		return fmt.Sprintf("Unsupported type: %s", kind.String())
	}
}

// CamelToSnake Hump conversion
func CamelToSnake(s string) string {
	var result []rune
	for i, c := range s {
		if unicode.IsUpper(c) && (i == 0 || !unicode.IsUpper(rune(s[i-1]))) {
			result = append(result, '_')
			c = unicode.ToLower(c)
		}
		result = append(result, c)
	}
	snakeStr := strings.ToLower(string(result))
	if snakeStr[0] == '_' {
		snakeStr = snakeStr[1:]
	}
	return snakeStr
}
